package com.tl.satoken.service;

import com.tl.satoken.domain.entity.Player;
import com.tl.satoken.domain.entity.Position;
import com.tl.satoken.domain.entity.RoomInfo;
import com.tl.satoken.domain.entity.RoomJoinResult;
import jakarta.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

@Service
public class RoomService {
    private static final Logger log = LoggerFactory.getLogger(RoomService.class);
    private static final int MAX_PLAYERS_PER_ROOM = 1000;
    private static final int GRID_WIDTH = 50;
    private static final int GRID_HEIGHT = 50;
    private static final String ROOM_PREFIX = "game:room:";
    private static final String PLAYER_PREFIX = "game:player:";
    private static final String ROOM_COUNTER = "game:room:counter";
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    public RoomService() {
    }

    @PostConstruct
    public void init() {
        this.cleanupOldData();
    }

    private void cleanupOldData() {
        try {
            log.info("清理旧的游戏数据...");
            Set<String> keys = this.redisTemplate.keys("game:*");
            if (keys != null && !keys.isEmpty()) {
                this.redisTemplate.delete(keys);
                log.info("清理了 {} 个旧的游戏数据", keys.size());
            }
        } catch (Exception e) {
            log.warn("清理旧数据时出现异常: {}", e.getMessage());
        }
    }

    public RoomJoinResult joinRoom(Player player) {
        log.info("玩家 {} 尝试加入房间", player.getUsername());

        try {
            String playerKey = "game:player:" + player.getId();
            if (Boolean.TRUE.equals(this.redisTemplate.hasKey(playerKey))) {
                return new RoomJoinResult(false, "玩家已在房间中", null);
            }
            
            String targetRoomId = this.findAvailableRoom();
            if (targetRoomId == null) {
                targetRoomId = this.createNewRoom();
                log.info("创建新房间: {}", targetRoomId);
            }

            String roomKey = "game:room:" + targetRoomId;
            Long roomSize = this.redisTemplate.opsForSet().size(roomKey);
            if (roomSize != null && roomSize >= 1000L) {
                return new RoomJoinResult(false, "房间已满", null);
            }
            
            Position startPos = this.generateRandomFreePosition(targetRoomId);
            player.setPosition(startPos);
            player.setRoomId(targetRoomId);
            player.setStatus("online");
            
            this.redisTemplate.opsForSet().add(roomKey, player.getId());
            this.redisTemplate.opsForValue().set(playerKey, targetRoomId);
            
            String playerHashKey = "game:player:" + player.getId() + ":data";
            this.redisTemplate.opsForHash().put(playerHashKey, "username", player.getUsername());
            this.redisTemplate.opsForHash().put(playerHashKey, "status", player.getStatus());
            Position pos = player.getPosition();
            if (pos != null) {
                Map<String, Integer> positionMap = new HashMap<>();
                positionMap.put("x", pos.getX());
                positionMap.put("y", pos.getY());
                this.redisTemplate.opsForHash().put(playerHashKey, "position", positionMap);
            }
            this.redisTemplate.opsForHash().put(playerHashKey, "roomId", player.getRoomId());
            
            log.info("玩家 {} 成功加入房间 {}, 当前房间人数: {}", player.getUsername(), targetRoomId, this.getRoomPlayerCount(targetRoomId));
            return new RoomJoinResult(true, "加入成功", targetRoomId);
            
        } catch (Exception e) {
            log.error("加入房间时出现异常: {}", e.getMessage(), e);
            return new RoomJoinResult(false, "加入房间失败: " + e.getMessage(), null);
        }
    }

    public boolean leaveRoom(String playerId) {
        try {
            String playerKey = "game:player:" + playerId;
            String roomId = (String)this.redisTemplate.opsForValue().get(playerKey);
            if (roomId == null) {
                return false;
            }
            
            String roomKey = "game:room:" + roomId;
            
            this.redisTemplate.opsForSet().remove(roomKey, playerId);
            
            this.redisTemplate.delete(playerKey);
            String playerHashKey = "game:player:" + playerId + ":data";
            this.redisTemplate.delete(playerHashKey);
            
            log.info("玩家 {} 离开房间 {}, 剩余人数: {}", playerId, roomId, this.getRoomPlayerCount(roomId));
            
            if (this.getRoomPlayerCount(roomId) == 0) {
                this.redisTemplate.delete(roomKey);
                log.info("房间 {} 已清空，删除房间", roomId);
            }

            return true;
        } catch (Exception e) {
            log.error("离开房间时出现异常: {}", e.getMessage(), e);
            return false;
        }
    }

    public List<Player> getPlayersInRoom(String roomId) {
        try {
            String roomKey = "game:room:" + roomId;
            
            Set<Object> playerIds = this.redisTemplate.opsForSet().members(roomKey);
            if (playerIds == null || playerIds.isEmpty()) {
                return new ArrayList();
            }
            
            List<Player> playerList = new ArrayList();
            
            for (Object obj : playerIds) {
                if (obj instanceof String) {
                    String playerId = (String) obj;
                    Player player = getPlayerById(playerId);
                    if (player != null) {
                        playerList.add(player);
                    }
                }
            }
            
            return playerList;
        } catch (Exception e) {
            log.error("获取房间玩家时出现异常: {}", e.getMessage(), e);
            return new ArrayList();
        }
    }
    
    private Player getPlayerById(String playerId) {
        try {
            String playerHashKey = "game:player:" + playerId + ":data";
            
            Map<Object, Object> playerData = this.redisTemplate.opsForHash().entries(playerHashKey);
            if (playerData.isEmpty()) {
                return null;
            }
            
            Player player = new Player();
            player.setId(playerId);
            
            if (playerData.get("username") != null) {
                player.setUsername((String) playerData.get("username"));
            }
            if (playerData.get("status") != null) {
                player.setStatus((String) playerData.get("status"));
            }
            if (playerData.get("position") != null) {
                try {
                    @SuppressWarnings("unchecked")
                    Map<String, Integer> positionMap = (Map<String, Integer>) playerData.get("position");
                    Integer x = positionMap.get("x");
                    Integer y = positionMap.get("y");
                    if (x != null && y != null) {
                        player.setPosition(new Position(x, y));
                    }
                } catch (Exception e) {
                    log.warn("无法解析位置信息: {}", playerData.get("position"));
                }
            }
            if (playerData.get("roomId") != null) {
                player.setRoomId((String) playerData.get("roomId"));
            }
            
            return player;
        } catch (Exception e) {
            log.error("获取玩家数据时出现异常: {}", e.getMessage(), e);
            return null;
        }
    }

    public int getRoomPlayerCount(String roomId) {
        try {
            String roomKey = "game:room:" + roomId;
            Long size = this.redisTemplate.opsForSet().size(roomKey);
            return size != null ? size.intValue() : 0;
        } catch (Exception e) {
            log.error("获取房间人数时出现异常: {}", e.getMessage(), e);
            return 0;
        }
    }

    public List<RoomInfo> getAllRooms() {
        try {
            List<RoomInfo> roomInfos = new ArrayList();
            Set<String> keys = this.redisTemplate.keys("game:room:*");
            if (keys != null) {
                for(String key : keys) {
                    if (!key.endsWith(":counter")) {
                        String roomId = key.substring("game:room:".length());
                        if (!"counter".equals(roomId)) {
                            RoomInfo roomInfo = this.getRoomInfo(roomId);
                            if (roomInfo != null) {
                                roomInfos.add(roomInfo);
                            }
                        }
                    }
                }
            }

            return roomInfos;
        } catch (Exception e) {
            log.error("获取所有房间时出现异常: {}", e.getMessage(), e);
            return new ArrayList();
        }
    }

    public RoomInfo getRoomInfo(String roomId) {
        try {
            int playerCount = this.getRoomPlayerCount(roomId);
            if (playerCount < 0) {
                return null;
            } else {
                return new RoomInfo(roomId, playerCount, 1000);
            }
        } catch (Exception e) {
            log.error("获取房间信息时出现异常: {}", e.getMessage(), e);
            return null;
        }
    }

    public boolean updatePlayerPosition(String playerId, Player updatedPlayer) {
        try {
            String playerKey = "game:player:" + playerId;
            String roomId = (String)this.redisTemplate.opsForValue().get(playerKey);
            if (roomId == null) {
                return false;
            }
            
            String roomKey = "game:room:" + roomId;
            
            Boolean isMember = this.redisTemplate.opsForSet().isMember(roomKey, playerId);
            if (!Boolean.TRUE.equals(isMember)) {
                log.warn("玩家 {} 不在房间 {} 中，无法更新位置", playerId, roomId);
                return false;
            }
            
            String playerHashKey = "game:player:" + playerId + ":data";
            
            Position pos = updatedPlayer.getPosition();
            if (pos != null) {
                Map<String, Integer> positionMap = new HashMap<>();
                positionMap.put("x", pos.getX());
                positionMap.put("y", pos.getY());
                this.redisTemplate.opsForHash().put(playerHashKey, "position", positionMap);
            }
            this.redisTemplate.opsForHash().put(playerHashKey, "status", updatedPlayer.getStatus());
            this.redisTemplate.opsForHash().put(playerHashKey, "roomId", updatedPlayer.getRoomId());
            
//            this.redisTemplate.expire(playerHashKey, 1, TimeUnit.HOURS);
            
            return true;
        } catch (Exception e) {
            log.error("更新玩家位置时出现异常: {}", e.getMessage(), e);
            return false;
        }
    }

    private String findAvailableRoom() {
        try {
            Set<String> keys = this.redisTemplate.keys("game:room:*");
            String targetRoomId = null;
            int maxPlayers = 0;
            if (keys != null) {
                for(String key : keys) {
                    if (key.endsWith(":counter")) {
                        continue;
                    }
                    
                    String roomId = key.substring("game:room:".length());
                    if (!"counter".equals(roomId)) {
                        int playerCount = this.getRoomPlayerCount(roomId);
                        if (playerCount < 1000 && playerCount >= maxPlayers) {
                            maxPlayers = playerCount;
                            targetRoomId = roomId;
                        }
                    }
                }
            }

            return targetRoomId;
        } catch (Exception e) {
            log.error("寻找可用房间时出现异常: {}", e.getMessage(), e);
            return null;
        }
    }

    private String createNewRoom() {
        try {
            if (!Boolean.TRUE.equals(this.redisTemplate.hasKey("game:room:counter"))) {
                this.redisTemplate.opsForValue().set("game:room:counter", 0L);
            }

            Long roomNumber = this.redisTemplate.opsForValue().increment("game:room:counter");
            String roomId = "Room_" + roomNumber;
            String roomKey = "game:room:" + roomId;
            
            this.redisTemplate.expire(roomKey, 3L, TimeUnit.DAYS);
            return roomId;
        } catch (Exception e) {
            log.error("创建新房间时出现异常: {}", e.getMessage(), e);
            return "Room_" + System.currentTimeMillis();
        }
    }

    private Position generateRandomFreePosition(String roomId) {
        try {
            String roomKey = "game:room:" + roomId;
            Set<Object> players = this.redisTemplate.opsForSet().members(roomKey);
            Set<String> occupied = new HashSet();
            if (players != null) {
                for(Object obj : players) {
                    if (obj instanceof Player) {
                        Player p = (Player)obj;
                        if (p.getPosition() != null) {
                            int var10001 = p.getPosition().getX();
                            occupied.add(var10001 + "," + p.getPosition().getY());
                        }
                    }
                }
            }

            Random random = new Random();

            for(int attempt = 0; attempt < 100; ++attempt) {
                int x = random.nextInt(GRID_WIDTH);
                int y = random.nextInt(GRID_HEIGHT);
                String key = x + "," + y;
                if (!occupied.contains(key)) {
                    return new Position(x, y);
                }
            }

            return new Position(0, 0);
        } catch (Exception e) {
            log.warn("生成随机位置失败，使用默认(0,0): {}", e.getMessage());
            return new Position(0, 0);
        }
    }

    public int getActiveConnections() {
        try {
            Set<String> keys = this.redisTemplate.keys("game:room:*");
            if (keys == null) {
                return 0;
            } else {
                int totalConnections = 0;

                for(String key : keys) {
                    if (!key.equals("game:room:counter")) {
                        Long size = this.redisTemplate.opsForSet().size(key);
                        if (size != null) {
                            totalConnections += size.intValue();
                        }
                    }
                }

                return totalConnections;
            }
        } catch (Exception e) {
            log.error("获取活跃连接数时出现异常: {}", e.getMessage(), e);
            return 0;
        }
    }

    public int getTotalPlayers() {
        try {
            Set<String> keys = this.redisTemplate.keys("game:room:*");
            if (keys == null) {
                return 0;
            } else {
                int totalPlayers = 0;

                for(String key : keys) {
                    if (!key.equals("game:room:counter")) {
                        Long size = this.redisTemplate.opsForSet().size(key);
                        if (size != null) {
                            totalPlayers += size.intValue();
                        }
                    }
                }

                return totalPlayers;
            }
        } catch (Exception e) {
            log.error("获取总玩家数时出现异常: {}", e.getMessage(), e);
            return 0;
        }
    }

    public RedisTemplate<String, Object> getRedisTemplate() {
        return this.redisTemplate;
    }
}
